package data_sync

import (
	"airport_container/data_sync/db"
	"context"
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"errors"
	pb "gitee.com/airport_container/grpc_interface/gosdk/data_sync"
	devPb "gitee.com/airport_container/grpc_interface/gosdk/device"
	jobPb "gitee.com/airport_container/grpc_interface/gosdk/job"
	log "github.com/sirupsen/logrus"
	"go.mongodb.org/mongo-driver/mongo"
	"google.golang.org/grpc"
	"io/ioutil"
	"net/http"
	"os"
	"strings"
	"time"
)

type DataSyncServe struct {
	pb.UnimplementedDataSyncServer
	syncInterval int
	dbStore      *db.MgoStore
	syncCloudImg bool
}

func NewServe(store *db.MgoStore, syncInterval int, syncCloudImg bool) pb.DataSyncServer {
	s := DataSyncServe{
		dbStore:      store,
		syncInterval: syncInterval,
		syncCloudImg: syncCloudImg,
	}
	go s.jobSync()
	return &s
}

func (s *DataSyncServe) jobSync() {
	for {
		//获取各个设备信息
		devs, err := s.dbStore.GetDevs()
		if err != nil {
			log.WithField("fn", "jobSync").Error("获取设备数据失败:", err)
			goto end
		}
		for _, dev := range devs {
			logger := log.WithFields(log.Fields{"fn": "jobSync", "名称": dev.Name, "Ip": dev.Ip})
			//获取设备未同步的作业
			jobs, err := s.getDevUnSyncJob(dev)
			if err != nil {
				logger.Error("getDevUnSyncJob:", err.Error())
				continue
			}
			for _, job := range jobs {
				err := s.saveJob(dev.Ip, job)
				if err != nil {
					logger.Info(job)
					logger.Error("saveJob err:", err.Error())
					break
				} else {
					logger.Debug("同步记录成功，taskId", job.TaskId)
				}
			}
		}
	end:
		time.Sleep(time.Duration(s.syncInterval) * time.Second)
	}
}

func (s *DataSyncServe) GetDataInfo(ctx context.Context, req *pb.GetDataInfoRequest) (*pb.GetDataInfoResponse, error) {
	var res pb.GetDataInfoResponse
	//员工
	users, err := s.dbStore.GetUsers()
	if err != nil {
		return nil, err
	}
	//容器
	containers, err := s.dbStore.GetContainers()
	if err != nil {
		return nil, err
	}
	//组板公司
	boardCompany, err := s.dbStore.GetBoardCompanys()
	if err != nil {
		return nil, err
	}
	//员工
	bs, _ := json.Marshal(users)
	hash := md5.Sum(bs)
	res.UserMd5 = hex.EncodeToString(hash[:])
	//容器
	bs, _ = json.Marshal(containers)
	hash = md5.Sum(bs)
	res.ContainerMd5 = hex.EncodeToString(hash[:])
	//组板公司
	bs, _ = json.Marshal(boardCompany)
	hash = md5.Sum(bs)
	res.BoardCompanyMd5 = hex.EncodeToString(hash[:])

	if res.UserMd5 != req.UserMd5 {
		res.Users = append(res.Users, users...)
	}
	if res.ContainerMd5 != req.ContainerMd5 {
		res.Containers = append(res.Containers, containers...)
	}
	if res.BoardCompanyMd5 != req.BoardCompanyMd5 {
		res.BoardCompany = append(res.BoardCompany, boardCompany...)
	}
	return &res, nil
}

func (s *DataSyncServe) getDevUnSyncJob(dev *devPb.DeviceModel) ([]*jobPb.JobModel, error) {
	logger := log.WithFields(log.Fields{"fn": "devSync", "名称": dev.Name, "Ip": dev.Ip})

	conn, err := grpc.Dial(dev.Ip+":1095", grpc.WithInsecure())
	if err != nil {
		logger.Error("grpc Dial err:", err.Error())
		return nil, err
	}
	defer conn.Close()
	syncClient := jobPb.NewJobClient(conn)

	lastJob, err := s.dbStore.GetLastJob()
	lastTestTime := "2024-01-01 00:00:00"
	if err != nil {
		if !errors.Is(err, mongo.ErrNoDocuments) {
			logger.Error("GetLastJob err:", err.Error())
			return nil, err
		}
	} else {
		lastTestTime = lastJob.TestTime
	}
	t, err := time.Parse("2006-01-02 15:04:05", lastTestTime)
	if err != nil {
		return nil, err
	}
	t0 := t.Add(time.Second).Format("2006-01-02 15:04:05")
	t1 := time.Now().Format("2006-01-02 15:04:05")

	logger = logger.WithFields(log.Fields{"t0": t0, "t1": t1})
	res, err := syncClient.ListJob(context.Background(), &jobPb.ListJobRequest{StartTime: t0, EndTime: t1})
	if err != nil {
		logger.Error("ListJob err:", err.Error())
		return nil, err
	}
	return res.Jobs, nil
}

func (s *DataSyncServe) saveJob(devIp string, job *jobPb.JobModel) error {
	//彩色图片1
	err := s.saveImg(devIp, job.ColorImg1)
	if err != nil {
		return errors.New("saveColorImg1 err:" + err.Error())
	}
	//彩色图片2
	err = s.saveImg(devIp, job.ColorImg2)
	if err != nil {
		return errors.New("saveColorImg2 err:" + err.Error())
	}
	//彩色图片3
	err = s.saveImg(devIp, job.ColorImg3)
	if err != nil {
		return errors.New("saveColorImg3 err:" + err.Error())
	}
	//彩色图片4
	err = s.saveImg(devIp, job.ColorImg4)
	if err != nil {
		return errors.New("saveColorImg4 err:" + err.Error())
	}
	//侧视图彩色图片
	err = s.saveImg(devIp, job.SideImg)
	if err != nil {
		return errors.New("saveSideImg err:" + err.Error())
	}
	//俯视图彩色图片
	err = s.saveImg(devIp, job.TopImg)
	if err != nil {
		return errors.New("saveTopImg err:" + err.Error())
	}

	if s.syncCloudImg == true {
		//彩色点云
		err = s.saveImg(devIp, job.ColorPointCloud)
		if err != nil {
			return errors.New("saveColorPointCloud err:" + err.Error())
		}
		//最终点云
		err = s.saveImg(devIp, job.PointCloud)
		if err != nil {
			return errors.New("savePointCloud err:" + err.Error())
		}
	}

	err = s.dbStore.CreateJob(job)
	if err != nil {
		return errors.New("CreateJob err:" + err.Error())
	}
	return nil
}

func (s *DataSyncServe) saveImg(ip, img string) error {
	url := strings.Replace(img, "D://", "http://"+ip+":1094/api/file/get_file/", -1)
	//请求文件
	res, err := http.Get(url)
	if err != nil {
		return err
	}
	defer res.Body.Close()
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return err
	}

	//创建对应的文件
	strs := strings.SplitAfter(img, "/")
	if len(strs) != 7 {
		return errors.New("文件名错误")
	}
	path := "files/" + strs[2] + strs[3] + strs[4] + strs[5]
	err = os.MkdirAll(path, os.ModePerm)
	if err != nil {
		return err
	}

	return os.WriteFile(path+strs[6], body, os.ModePerm)
}
